#pragma once

#include <base.h>

/* C编译器语法糖 */

/* pragma 相关 */
#define PRAGMA(x)			_Pragma(#x)
#define MPUSH(X)			PRAGMA(push_macro(#X))
#define MPOP(X)				PRAGMA(pop_macro(#X))
#define PRAGMA_COMPL(x)			PRAGMA(GCC x)

#define TODO(x) 			PRAGMA(message ("TODO - " #x))
#define ERORR_COMPL(x)			PRAGMA(error ("[error] " #x ))

/* 静态断言 */
#define __SASSERT_TOSTRING(exp)		TO_STRING([SASSERT]: assert exp failed at ) __FILE__ ":" TO_STRING(__LINE__)
#define SASSERT_FAIL(exp, error)	_Static_assert(exp, error)
#define SASSERT(exp)			SASSERT_FAIL(exp, __SASSERT_TOSTRING(exp))

/* 判断变量var是否有attribute */
#define ATTR_EXISTS(var, attr)		__builtin_has_attribute(var, attr)
/* 可用于检查变量是否对齐 */

/* 命名汇编函数 */
#define SRENAME(old_name, new_name_asm)	PRAGMA(redefine_extname old_name new_name_asm)

/* 函数调用相关 https://gcc.gnu.org/onlinedocs/gcc/Constructing-Calls.html#Constructing-Calls */

/* 编译器抽象层 */
/* ----------------------------------------------------------------
 * 以下为提示编译器优化的属性 */

/* 用于分支预测优化 */
#define UNLIKELY(x)			__builtin_expect(!!(x), 0)
#define LIKELY(x)			__builtin_expect(!!(x), 1)
/* 指定概率 */
#define PREDICT(x, val, prob)		__builtin_expect_with_probability(!!(x), val, prob)

/* 较常执行的函数 */
#define HOT				__attribute__((hot))
#define COLD				__attribute__((cold))

/* 告诉编译器用于对齐优化，后面可以指定第n个参数，第二个参数...的对齐值 */
#define ASUME_ALIGNED(arg, ...)		__builtin_assume_aligned(arg, __VA_ARGS__)

/* 预取,可传3个参数, rw和locallity, rw表示数据要被都或者写,
locality 取值0-3表示数据的局部性，3表示数据的局部性最高应该尽可能放在cache里 */
#define PREFETCH(...)			__builtin_prefetch(__VA_ARGS__)

/* 启用了指定编译选项时使用本函数, 详见 https://lwn.net/Articles/691932/ */
#define TARGET_CLONES(option)		__attribute__((target_clones(#option)))

/* 告诉编译器参数已使用 */
#define __PARAM_USED(x)			((void )x);
#define PARAM_USED(...)			MAP(__PARAM_USED, __VA_ARGS__)

/* 告诉编译器函数参数非空 */
#define PARAM_NONULL(...)		__attribute__((nonnull (__VA_ARGS__)))
/* 告诉编译器函数返回值非非空 */
#define RETURN_NONULL			__attribute__((returns_nonnull))
/* 告诉编译器函数指定参数是大小和对齐值 */
#define ALLOCPARM_SIZE(...)		__attribute__((alloc_size(__VA_ARGS__)))
#define ALLOCPARM_ALIGN(...)		__attribute__((alloc_align(__VA_ARGS__)))

/* 标记使用 */
#define MAY_UNUSED			__attribute__((unused))
#define USED				__attribute__((used))

/* 标记纯函数，纯函数不会对系统全局状态产生影响 编译器会自动替换为同一个参数调用的值 */
#define PURE         			__attribute__((__pure__))

/* 标记常量函数，比纯函数更严格 */
#define CONST				__attribute__ ((const))

/* 叶子函数，有很多控制流跳转的限制 */
#define LEAF				__attribute__((leaf))

/* 标记为中断处理函数 */
#define INTERRUPT			__attribute__((interrupt))

/* 函数可能被两次返回，用于可能多次恢复并返回的setjmp的函数，编译器确保所有寄存器都被使用 */
#define RETURN_TWICE			__attribute__((returns_twice))

/* ----------------------------------------------------------------
 * 以下为改变编译行为的关键属性 */

/* 用于对齐 */
#define ALIGN(n)			__attribute__((aligned(n)))
#define CACHE_ALIGNED 			ALIGN(HDEF_CACHE_LINE_BYTES)
#define PAGE_ALIGNED 			ALIGN(PAGE_SIZE)

/* 紧凑数据结构	*/
#define PACKED				__attribute__((packed))

/* 用于控制函数inline */
#define ALWAYS_INLINE			inline __attribute__((always_inline))
#define NOINLINE			__attribute__((noinline))

/* 语法糖 */
#define	SU				USED static

#define SAI				static ALWAYS_INLINE /* MAY_UNUSED */
#define PSAI				PURE static ALWAYS_INLINE
#define CSAI				CONST static ALWAYS_INLINE

#define SIN				static inline
#define PSIN				PURE static inline
#define CSIN				CONST static inline

#define SNI				static NOINLINE
#define INL				inline
#define NOI				NOINLINE

/* 该属性标记的函数中所有的调用将会被inline */
#define FLATTEN				__attribute__((flatten))

#define UNROLL_LOOPS			__attribute__((optimize("unroll-loops")))
#define NO_UNROLL			__attribute__((optimize("no-unroll-loops")))

/* 提示编译器为inline函数生成调试信息，同时INLINED BODY使用调用者空间 */
#define INLINE_ARTIFICIAL		__attribute__((artificial))

/* 设置符号隐藏 */
#define HIDDEN 				__attribute__((visibility("hidden")))
#define VISIBLE 			__attribute__((visibility("visible")))

/* 设置函数是否有prologue和epilogue */
#define NAKED				__attribute__((naked))
/* 不产生函数返回值 */
#define NORETURN			__attribute__((__noreturn__))

/* 不可达位置 */
#define UNREACHABLE()  			__builtin_unreachable()

/* 生成非法代码产生陷入 */
#define TRAP()				__builtin_trap()

/* 假设成立，用于编译器优化 */
#define ASSUME(cond) 			__builtin_assume(cond)

#define SECTION(sec) 			__attribute__((__section__(sec)))

/* 优化设置代码优化级别 */
#define OPTIMIZE(x)			__attribute__((optimize(x)))
/* ----------------------------------------------------------------
 * 以下为提示编译器静态检查和调试的属性 */

/* 检查printf等参数格式是否正确,第一个是检查类型，可以是printf, scanf, strftime, gnu_printf,
 * gnu_scanf, gnu_strftime, strfmon。第二个是fmt所在参数个数，第三个是arg参数格式 */
#define CHECK_FORMAT(type, fmtidx, argidx) \
	__attribute__((format(type, fmtidx, argidx)))
#define CHECK_FORMAT_PRINTF(fmtidx, argidx) \
	CHECK_FORMAT(printf, fmtidx, argidx)

/* ----------------------------------------------------------------
 * 以下为宏函数 */


/* ((size_t) &((type *)0)->member) */
#define offsetof(type, member)		__builtin_offsetof(type, member)
#define OFFSETOF(type, member)		offsetof(type, member)

/* 获得指针指向的大小，如果不能在编译时获得返回 -1， 第二个参数是函数类型，如果是0则返回-1，如果是2和3则返回0。
 如果ptr在编译时有多个0，则取最大的？*/
#define sizeof_obj(ptr)			__builtin_object_size(ptr, 0)
/* 可能通过运行时检测获得对象大小, 第二个参数是如果不能获得大小时的返回值 */
#define get_objsize(ptr, type)		__builtin_dynamic_object_size(ptr, -1)
/* 获得对象的对齐字节 */
#define align_of(ptr)			__alignof__(ptr)
/* 能否常量求值 */
#define CAN_EVAL(exp)			__builtin_constant_p(exp)
/* TIF */
#define TIF_ELSE(expr, exp1, exp2)	__builtin_choose_expr(expr, exp1, exp2)

#define TCOND_UNREACHABLE		((void)0)
/* 判断类型是否相等 */
#define IS_SAMETYPE(a, b)		__builtin_types_compatible_p(typeof(a), typeof(b))


/* stdarg参数处理 */
#define __va_start(v,l)			__builtin_va_start(v,l)
#define __va_end(v)			__builtin_va_end(v)
#define __va_arg(v,l)			__builtin_va_arg(v,l)
typedef __builtin_va_list		__va_list_t;

/* 函数调用相关 */
#define FUNC_CUR_ARGS()			__builtin_apply_args()
#define FUNC_EXEC(func, arg, asize)	__builtin_apply(func, arg, asize)
#define FUNC_RET(val)			__builtin_return(val)
#define INLFUNC_ARG()			__builtin_va_arg_pack_len()
#define INLFUNC_ARG_LEN()		__builtin_va_arg_pack_len()

/* 声明某个函数的非inline形式 */
#define DECL_NONINL(inl_func, new_func) \
	__typeof__(inl_func) new_func

#define __memset(ptr, val, size)	__builtin_memset(ptr, val, size)
#define __memcpy(dest, src, size)	__builtin_memcpy(dest, src, size)
#define __memcmp(dest, src, size)	__builtin_memcmp(dest, src, size)


/* 裸机不能使用 */
#define TLS_INITIAL			__attribute__((tls_model("initial-exec"))) __thread

/* 检查溢出 */
#define ADD_CHKOVF(a, b, pres)		__builtin_add_overflow (a, b, pres)
#define SUB_CHKOVF(a, b, pres)		__builtin_sub_overflow (a, b, pres)
#define MUL_CHKOVF(a, b, pres)		__builtin_mul_overflow (a, b, pres)


// #define TYPE_ASSERT(X,Y) 	_Generic ((Y), \
//     __typeof__(X): _Generic ((X), \
//         __typeof__(Y): (void)NULL \
//     ) \
// )

/* 实现泛型的基础代码，避免长判断，必须使用递归解析 */
// #define GENERIC_TYPESIZE_ID()		TCOND_UNREACHABLE()

// #define __GENERIC_TYPESIZE(x, type, func, ...)	\
// 		TIF_ELSE(sizeof(x) == sizeof(type), func(x), GENERIC_TYPESIZE_ID())


// #define GENERIC_TYPESIZE(x, type, func, ...) 	\
// 		(TIF_ELSE(sizeof(x) == sizeof(type), func(x), _GENERIC_TYPESIZE(x, __VA_ARGS__)))

// #define _GENERIC_TYPESIZE(x, type, func, ...)	\
// 		(TIF_ELSE(sizeof(x) == sizeof(type), func(x), __VA_OPT__(GENERIC_TYPESIZE(x, __VA_ARGS__)) ))

// #define GENERIC_TYPESIZE(int_func, long_func, llong_func) \
// 	(TIF_ELSE(sizeof(x) == sizeof(int), __CLZ(x),			\
//                 					TIF_ELSE(sizeof(x) == sizeof(long), __CLZL(x), 			\
//                     				TIF_ELSE(sizeof(x) == sizeof(long long), __CLZLL(x), 	\
//                         			, TCOND_UNREACHABLE) 									\
//                     						) 												\
//                 							) 												\
//             						)
/* TODO:TIF_ELSE能不能展开写? */


